﻿
using UnityEngine;

namespace CWM.Skinn
{
    public static partial class SkinnEx
    {
        public static class UMATextureConverter
        {
            private static Mesh quad = null;
            private static Mesh Quad
            {
                get
                {
                    if (!quad)
                    {
                        GameObject temp = GameObject.CreatePrimitive(PrimitiveType.Quad);
                        quad = temp.GetComponent<MeshFilter>().sharedMesh;
                        Release(temp);
                    }
                    return quad;
                }
            }

            private static Material cutoutMaterial = null;
            private static Material CutoutMaterial
            {
                get
                {
                    if (cutoutMaterial == null)
                    {
                        string shaderName = "Hidden/UVSwapCutout";
                        Shader shader = Shader.Find(shaderName);
                        if (shader == null)
                        {
                            Debug.LogError(string.Format("Missing Shader \"{0}\"", shaderName));
                            return cutoutMaterial;
                        }
                        cutoutMaterial = new Material(shader)
                        {
                            name = "UVSwapCutout",
                            hideFlags = HideFlags.HideAndDontSave
                        };
                    }
                    return cutoutMaterial;
                }
            }

            private static Material rgbaMaterial = null;
            private static Material RGBAMaterial
            {
                get
                {
                    if (rgbaMaterial == null)
                    {
                        string shaderName = "Hidden/UVSwapRGBA";
                        Shader shader = Shader.Find(shaderName);
                        if (shader == null)
                        {
                            Debug.LogError(string.Format("Missing Shader \"{0}\"", shaderName));
                            return rgbaMaterial;
                        }
                        rgbaMaterial = new Material(shader)
                        {
                            name = "UVSwapRGB",
                            hideFlags = HideFlags.HideAndDontSave
                        };
                    }
                    return rgbaMaterial;
                }
            }

            private static readonly int sampleResolution = 2;
            private static Texture2D sampleTexture = null;
            private static Texture2D SampleTexture
            {
                get
                {
                    if (sampleTexture == null)
                    {
                        sampleTexture = new Texture2D(sampleResolution, sampleResolution)
                        {
                            name = "SampleTexture",
                            hideFlags = HideFlags.HideAndDontSave
                        };

                    }
                    return sampleTexture;
                }
            }

            private static RenderTexture uvRenderTexture = null;

            public static void Dispose()
            {
                Release(uvRenderTexture);
                Release(cutoutMaterial);
                Release(rgbaMaterial);
                Release(sampleTexture);
                Release(uvRenderTexture);

            }

            public static RenderTexture ConvertTexture(Mesh uvMesh, Texture texture, RenderTextureFormat renderTextureFormat)
            {
                Mesh mesh = uvMesh;
                if (!mesh || !CutoutMaterial || !RGBAMaterial) return null;

                int width = texture.width;
                int height = texture.height;
                if (uvRenderTexture == null)
                {
                    uvRenderTexture = new RenderTexture(width, height, 0, renderTextureFormat, RenderTextureReadWrite.sRGB);
                }
                else if (uvRenderTexture.width != width || uvRenderTexture.height != height || uvRenderTexture.format != renderTextureFormat)
                {
                    if (uvRenderTexture) Release(uvRenderTexture);
                    uvRenderTexture = new RenderTexture(width, height, 0, renderTextureFormat, RenderTextureReadWrite.sRGB);
                }

                bool renderPadding;
                Material mat;

                bool alpha = true;
                if(alpha){
                    mat = CutoutMaterial;
                    renderPadding = RenderPadding(texture);
                }
                {
                    mat = RGBAMaterial;
                    renderPadding = true;
                }

                RenderTexture active = RenderTexture.active;
                RenderTexture.active = uvRenderTexture;
                {
                    GL.Clear(true, true, new Color(0.5f, 0.5f, 0.5f, 0f));
                    mat.SetTexture("_MainTex", texture);
                    for (int ii = 0; ii < mat.passCount; ii++) mat.SetPass(ii);

                    if (renderPadding) Graphics.DrawMeshNow(Quad, Matrix4x4.identity, 0);
                    for (int ii = 0; ii < mesh.subMeshCount; ii++) Graphics.DrawMeshNow(mesh, Matrix4x4.identity, ii);
                }
                RenderTexture.active = active;

                return uvRenderTexture;
            }

            private static bool RenderPadding(Texture texture)
            {
                RenderTexture active = RenderTexture.active;
                RenderTexture temp = RenderTexture.GetTemporary(sampleResolution, sampleResolution, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
                RenderTexture.active = temp;
                Graphics.Blit(texture, temp);
                SampleTexture.ReadPixels(new Rect(0, 0, sampleResolution, sampleResolution), 0, 0);
                SampleTexture.Apply();
                RenderTexture.active = active;
                RenderTexture.ReleaseTemporary(temp);
                Color color = SampleTexture.GetPixel(0, 0);
                if (color.a < 1f) return false;
                return true;
            }

        }
    }
}